
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_HASH_H_INCLUDED_
#define _NGX_HASH_H_INCLUDED_


#include <ngx_config.h>
#include <ngx_core.h>


typedef struct {
    void             *value;
    u_short           len;
    u_char            name[1];
} ngx_hash_elt_t; //fzc: 散列表的元素


typedef struct {
    ngx_hash_elt_t  **buckets;
    ngx_uint_t        size; //fzc: 散列表中的bucket个数
} ngx_hash_t; //fzc: 基本的散列表, 初始化的过程: 1. 将需要散列的数据按key/value对push到由ngx_hash_key_t构成数组, 2.再用ngx_hash_init方法将该数组转换为一个hash表即ngx_hash_t


typedef struct {
    ngx_hash_t        hash;
    void             *value;
} ngx_hash_wildcard_t; //fzc: 通配符散列表, 要么前置要么后置, 初始化过程类似ngx_hash_t, 但是用ngx_hash_wildcard_init


typedef struct {
    ngx_str_t         key; //fzc: 元素关键字
    ngx_uint_t        key_hash; //fzc: 关键字经散列方法后的值, 在ngx_hash_add_key中写死了ngx_hash_key方法
    void             *value; //fzc: 指向实际的用户数据
} ngx_hash_key_t; //fzc: 用来初始化哈希表ngx_hash_t/ngx_hash_combined_t, 也用在ngx_hash_keys_arrays_t相关的逻辑中
//fzc: 用在ngx_hash_keys_arrays_t中时, 作为其成员keys/dns_wc_head/dns_wc_tail数组的元素, 然后用ngx_hash_keys_arrays_t的三个ngx_hash_key_t数组分别初始化ngx_hash_combined_t哈希表中的三个成员

typedef ngx_uint_t (*ngx_hash_key_pt) (u_char *data, size_t len); //fzc: 散列方法的原型, 用户可以自定义散列方法


typedef struct {
    ngx_hash_t            hash; //fzc: 精确匹配散列表 
    ngx_hash_wildcard_t  *wc_head; //fzc: 前置通配符散列表
    ngx_hash_wildcard_t  *wc_tail; //fzc: 后置通配符散列表
} ngx_hash_combined_t; //fzc: 包含精确匹配和前置后置通配符匹配的散列表


typedef struct {
    ngx_hash_t       *hash;
    ngx_hash_key_pt   key; //fzc: hash function

    ngx_uint_t        max_size; //fzc: 表中bucket的个数
    ngx_uint_t        bucket_size; //fzc: 一个bucket的大小

    char             *name; //fzc: 散列表的名字
    ngx_pool_t       *pool; //fzc: 分配散列表的内存池中的bucket
    ngx_pool_t       *temp_pool;
} ngx_hash_init_t; //fzc: 用于初始化散列表的结构体, 传入到ngx_hash_init方法

//fzc: 在ngx_hash_keys_array_init中使用
#define NGX_HASH_SMALL            1
#define NGX_HASH_LARGE            2

#define NGX_HASH_LARGE_ASIZE      16384
#define NGX_HASH_LARGE_HSIZE      10007
//fzc: 在ngx_hash_add_key中使用
#define NGX_HASH_WILDCARD_KEY     1
#define NGX_HASH_READONLY_KEY     2


typedef struct {
    ngx_uint_t        hsize; //fzc: bucket的个数

    ngx_pool_t       *pool;
    ngx_pool_t       *temp_pool; //fzc: 下面的array都是由该内存池分配

    ngx_array_t       keys; //fzc: 元素为ngx_hash_key_t
    ngx_array_t      *keys_hash; //fzc: 二维数组, 数组元素是ngx_str_t即key, 多个key构成一个bucket, 用来加速相同key的检测即冲突,下面的dns_wc_head/dns_wc_head_hash, dns_wc_tail/dns_wc_tail_hash逻辑相同, 参见ngx_hash_add_key代码

    ngx_array_t       dns_wc_head;
    ngx_array_t      *dns_wc_head_hash;

    ngx_array_t       dns_wc_tail;
    ngx_array_t      *dns_wc_tail_hash;
} ngx_hash_keys_arrays_t; //fzc: 本质是三种ngx_hash_key_t数组的集合, 且利用hash的思想来实现关键字不重复(keys_hash,dns_wc_head_hash,dns_wc_tail_hash的存在分别是为了保证keys,dns_wc_head,dns_wc_tail数组中的ngx_hash_key_t不重复), 用ngx_hash_keys_array_init初始化, 用ngx_hash_add_key增加key/value, 查询是用哪个?


typedef struct {
    ngx_uint_t        hash;
    ngx_str_t         key;
    ngx_str_t         value;
    u_char           *lowcase_key;
} ngx_table_elt_t; //fzc: 存放http header项, 如在ngx_http_process_request_headers中将解析到的请求头部包装为ngx_table_elt_t放到r->headers_in->headers


void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len);
void *ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len);
void *ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len);
void *ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key,
    u_char *name, size_t len);

ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
    ngx_uint_t nelts);
ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
    ngx_uint_t nelts);

#define ngx_hash(key, c)   ((ngx_uint_t) key * 31 + c)
ngx_uint_t ngx_hash_key(u_char *data, size_t len);
ngx_uint_t ngx_hash_key_lc(u_char *data, size_t len);
ngx_uint_t ngx_hash_strlow(u_char *dst, u_char *src, size_t n);


ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type);
ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
    void *value, ngx_uint_t flags);


#endif /* _NGX_HASH_H_INCLUDED_ */
